import java.util.ArrayList;

import javax.swing.JOptionPane;
/**
 * This class represents the party that is travelling
 * 
 * @author samkim
 *
 */
public class Party {
	GameSystem system;
	private Leader leader;
	private ArrayList<Member> travellers;
	private int water, food, ammunition, money, weight, distance;
	private ArrayList<Item> inventory;
	private int capacity = 200;
	private Location current;
	private Ration rations;
	private Pace pace;
	private Weapon weapon;
	private ArrayList<RandomEvent> modifiers;
	private boolean noSupply;
	
	public Party(GameSystem system) {
		this.system = system;
		this.leader = new Leader();
		this.travellers = new ArrayList<Member>();
		this.water = 100;
		this.food = 50;
		this.distance = 0;
		this.current = system.getMap().getLocationList().get(0);
		this.money = 300;
		this.inventory = new ArrayList<Item>();
		this.weapon = Weapon.none;
		this.noSupply = false;
		this.capacity = 200;
		modifiers = new ArrayList<RandomEvent>();
	}
	
	public boolean getNoSupply() {
		return noSupply;
	}

	
	public ArrayList<Item> getInventory() {
		return inventory;
	}

	public void setInventory(ArrayList<Item> inventory) {
		this.inventory = inventory;
	}

	/**
	 * Adds item to party's inventory
	 * 
	 * @param item Item to be inserted
	 */
	public void addToInventory(Item item) {
		if (!inventory.contains(item))
			inventory.add(item);
	}
	
	public int getWeight() {
		return weight;
	}

	public void setWeight(int weight) {
		this.weight = weight;
	}
	
	/**
	 * Updates weight according to how much amount is inserted
	 * 
	 * @param amount Amount to be added to current weight
	 * @return True if successfully updated weight
	 * 			False if weight exceeds capacity if updated
	 */
	public boolean updateWeight(int amount) {
		if (weight + amount < capacity && weight + amount >= 0) {
			this.weight += amount;
			return true;
		}
		else
			return false;
	}
	
	/**
	 * Updates money according to amount inserted
	 * 
	 * @param amount Amount to be added to current money
	 * @return True if successfully updated money
	 * 			False if money runs out when updated
	 */
	public boolean updateMoney(int amount) {
		if (money+amount >= 0) {
			this.money += amount;
			return true;
		}
		else
			return false;
	}
	public int getMoney() {
		return money;
	}
	public void setMoney(int money) {
		this.money = money;
	}
	public int getAmmunition() {
		return ammunition;
	}
	public void setAmmunition(int ammunition) {
		this.ammunition = ammunition;
	}

	public Weapon getWeapon() {
		return weapon;
	}
	public void setWeapon(Weapon weapon) {
		this.weapon = weapon;
	}
	
	public void setWeapon(String weapon) {
		if(weapon.equals("none"))
			setWeapon(Weapon.none);
		if(weapon.equals("knife"))
			setWeapon(Weapon.knife);
		if(weapon.equals("k1"))
			setWeapon(Weapon.k1);
		if(weapon.equals("m16"))
			setWeapon(Weapon.m16);
		if(weapon.equals("ak47"))
			setWeapon(Weapon.ak47);
	}
	public int getDistance(){
		return this.distance;
	}
	
	
	/**
	 * Updates food and water
	 * @param ration
	 */
	public void eat(int ration) {
		int consume = ration;
		if(system.getParty().getLeader().getOccupation().equals(Occupation.COOK))
		{
			consume = ration/2;
		}
		if(food>=consume)
			food = food - consume;
		else {
			food = 0;
			noSupply = true;
		}
		if(water>=ration)
			water = water - consume;
		else {
			water = 0;
			noSupply = true;
		}
	}
	
	/**
	 * Updates updates current diatnace.
	 * @param walk
	 */
	private void walk(int walk) {
		
		if (current.isLastCity())
			return;
		
		while (walk>0) {
				current = current.getNext();
				walk--;
				distance++;
				if(current.hasWater==true)
				{
					break;
				}
				if (current.pickUpRandomEvents(this))
					break;
				if (current instanceof City)
					break;
				
		}
	
	}
	
	private void walk() {
		int toWalk = pace.work;
		for (RandomEvent r:modifiers)
			if (r instanceof SpeedModifier)
				toWalk = ((SpeedModifier) r).modifySpeed(toWalk);
		walk(toWalk);
		System.out.println(toWalk);
	}
	
	public boolean thereIsAStorm() {
		return current.thereIsAStorm();
	}

	/**
	 * Calls walk accordingly to the pace
	 */
	public void day() {
		if (this.rations == Ration.none){
			eat(0);
			for (int i=0; i<travellers.size(); i++) {
				if (travellers.get(i).getAlive() == true) {
					travellers.get(i).updateHealth(-(int)(10 * Math.random()));
					if (travellers.get(i).getHealth() <= 0) {
						system.getParty().killPlayer(i);
					}
				}
			}
		}
		else if (this.rations == Ration.poor) {
			eat(5);
			for (int i=0; i<travellers.size(); i++) {
				if (travellers.get(i).getAlive() == true) {
					travellers.get(i).updateHealth(-(int)(5 * Math.random()));	// decrease health
					if (travellers.get(i).getHealth() <= 0) {
						system.getParty().killPlayer(i);
					}
				}
			}
		}
		else if (this.rations == Ration.meager)
			eat(10);
		else if (this.rations == Ration.good) {
			eat(15);
			for (int i=0; i<travellers.size(); i++) {
				if (travellers.get(i).getAlive() == true)
					travellers.get(i).updateHealth((int)(5 * Math.random()));	// increase health
			}
		}
		
		if (this.pace == Pace.slow) {
			for (int i=0; i<travellers.size(); i++) {
				if (travellers.get(i).getAlive() == true) {
					travellers.get(i).updateHealth((int)(5 * Math.random()));	// decrease health
					if (travellers.get(i).getHealth() <= 0) {
						system.getParty().killPlayer(i);
					}
				}
			}
		}
		else if (this.pace == Pace.steady) {}
		else if (this.pace == Pace.grueling) {
			for (int i=0; i<travellers.size(); i++) {
				if (travellers.get(i).getAlive() == true)
					travellers.get(i).updateHealth(-(int)(5 * Math.random()));	// increase health
			}
		}
		
		walk();
	
		RandomEvent[] deadList = new RandomEvent[modifiers.size()];
		int deadCount = 0;
		boolean isDead;
		for (RandomEvent r:modifiers) {
			r.decay();
			isDead = r.isDead();
			if (isDead) {
				deadList[deadCount] = r;
				deadCount++;
			}
		}
		
		for (int i=0; i<deadCount; i++) {
			modifiers.remove(deadList[i]);
				
		}
	}
	
	public void addTraveller(Member traveller) {
		this.travellers.add(traveller);
	}

	public Leader getLeader() {
		return leader;
	}

	public GameSystem getSystem() {
		return system;
	}

	public void setSystem(GameSystem system) {
		this.system = system;
	}

	public int getWater() {
		return water;
	}

	public void setWater(int water) {
		this.water = water;
	}

	public int getFood() {
		return food;
	}

	public void setFood(int food) {
		this.food = food;
	}

	public Location getCurrent() {
		return current;
	}

	public void setCurrent(Location current) {
		this.current = current;
	}

	public Ration getRations() {
		return rations;
	}

	public void setRations(Ration rations) {
		this.rations = rations;
	}

	public Pace getPace() {
		return pace;
	}

	public void setPace(Pace pace) {
		this.pace = pace;
	}

	public void setTravellers(ArrayList<Member> travellers) {
		this.travellers = travellers;
	}

	public void setLeader(Leader leader) {
		this.leader = leader;
	}

	public ArrayList<Member> getTravellers() {
		return travellers;
	}

	public void setMembers(ArrayList<Member> members) {
		this.travellers = members;
	}
	
	public void updateWater(int amount) {
		water = water + amount;
		noSupply = false;
	}
	
	public void updateFood(int amount) {
		food = food + amount;
		noSupply = false;
	}
	
	public void updateAmmunition(int amount) {
		ammunition = ammunition + amount;
	}
	
	public boolean hasWireCutters() {
		for (Item i:this.getInventory())
			if (i.isWireCutters())
				return true;
		return false;
	}
	
	
	public enum Ration {
		none(0),
		poor(5),
		meager(10),
		good(15);
		
		private int ration;
		
		Ration(int ration) {
			this.ration = ration;
		}
		
		public void consumeFood(Party p) {
			p.eat(ration);
		}
	}
	
   /**************************8
    * I'm coding in the cloud, woooooh! Enums are great!
    *@author Jeoffrey Spinoza
    ***************************/
	public enum Pace {
		slow(5),
		steady(10),
		grueling(15);
		
		private int work;
		
		Pace(int work) {
			this.work = work;
		}
		
		public void makeTired(Party p) {
			p.walk(work);
		}

		public int getWork() {
			return work;
		}

		public void setWork(int work) {
			this.work = work;
		}
	}
	
	public static enum Weapon {
		none,
		knife,
		k1,
		m16,
		ak47;
	}

	public void addRandomEvent(RandomEvent r) {
		if (weHaveAJeep() && (r instanceof BarbedWire))
			return;
		if (this.thereIsAStorm() && (r instanceof Rain))
			return;
		else if (thereIsRain() && (r instanceof Rain))
			augmentRain((Rain)r);
		modifiers.add(r);
		r.decay();
		
	}
	
	private boolean weHaveAJeep() {
		for (RandomEvent re:modifiers)
			if (re instanceof Jeep)
				return true;
				
		return false;
	}

	private boolean thereIsRain() {
		for (RandomEvent re:modifiers)
			if (re instanceof Rain)
				return true;
				
		return false;
	}

	private void augmentRain(Rain r) {
		Rain rain = null;
		for (RandomEvent re:modifiers)
			if (re instanceof Rain)
				rain = (Rain)re;
		if (rain != null)
			rain.addDuration((Rain)r);
			
		
	}

	public void killPlayer(String name){
		for(int i=0; i<travellers.size();i++)
		{
			if(travellers.get(i).getName().equals(name))
			{
				travellers.get(i).setHealth(0);
				travellers.get(i).setAlive(false);
				travellers.get(i).setPrinted(true);
//				travellers.get(i).setName(travellers.get(i).getName()+" (KIA)");
			}
		}
	}
	public void killPlayer(int i){
		travellers.get(i).setHealth(0);
		travellers.get(i).setAlive(false);
		if(leader.getOccupation().equals(Occupation.MEDIC)&&Math.random()>0.5)
		{
			travellers.get(i).setHealth(40);
			travellers.get(i).setAlive(true);
			JOptionPane.showMessageDialog(null, "Thanks to our medic "+leader.getName()+", "+travellers.get(i).getName()+" was able to survive a fatal condition.");
		}
//		travellers.get(i).setPrinted(true);
//		travellers.get(i).setName(travellers.get(i).getName()+" (KIA)");
	}

	public void setDistance(int i) {
		this.distance=i;
		
	}

	public ArrayList<RandomEvent> getRandomEvents() {
		return modifiers;
	}

	public void killEveryone() {
		for(Traveller t:travellers)
			if (t instanceof Member)
				((Member) t).kill();
		
	}

	public void detour() {
		if(leader.getOccupation().equals(Occupation.RANGER))
		{
			JOptionPane.showMessageDialog(null, "Thanks to our ranger "+leader.getName()+", the detour only took 2 days.");
			getSystem().decDay();
			getSystem().decDay();
		}
		getSystem().decDay();
		getSystem().decDay();
		getSystem().decDay();
		getSystem().decDay();
		
		
	}
	
	public int getCapacity()
	{
		return this.capacity;
	}
	public void setCapacity(int i){
		this.capacity = i;
	}

	public Item getWireCutters() {
		for (Item i:inventory)
			if (i.isWireCutters())
				return i;
		return null;
	}
}
